package org.bronycorps.mlptss.manager.scripting;

import java.util.ArrayList;
import java.util.HashMap;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.bronycorps.mlptss.MlpTss;
import org.bronycorps.mlptss.domain.model.script.IScheduleScript;
import org.bronycorps.mlptss.domain.model.script.SpecialMissileScriptMediator;
import org.bronycorps.mlptss.manager.TrajectFactory;
import org.bronycorps.mlptss.manager.preferences.AssetsConfiguration.CharacterConfiguration;
import org.bronycorps.mlptss.manager.preferences.AssetsConfiguration.SpecialAttackConfiguration;
import org.bronycorps.mlptss.manager.preferences.GameConfiguration;

import aurelienribon.tweenengine.BaseTween;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenCallback;
import aurelienribon.tweenengine.TweenManager;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;

public class ScriptManager {

	private static ScriptManager instance;

	public static ScriptManager getInstance() {
		if (instance == null) {
			instance = new ScriptManager();
		}

		return instance;
	}

	public static void scheduleScript(ScriptEngine script,
			final SpecialMissileScriptMediator jsStage) {
		final Invocable inv = (Invocable) script;
		final Object schedulerObj = script.get("scheduler");
		IScheduleScript scheduler = inv.getInterface(schedulerObj,
				IScheduleScript.class);

		float[] times = scheduler.getTimes(jsStage);
		String[] methods = scheduler.getMethods(jsStage);
		Object[] params = scheduler.getParameters(jsStage);

		TrajectFactory trajectFactory = TrajectFactory.getInstance();
		TweenManager tweenManager = trajectFactory.getTweenManager();
		for (int i = 0; i < scheduler.getSize(jsStage); i++) {
			final String currentMethod = methods[i];
			final Object currentParam;
			if (params != null && params.length > i) {
				currentParam = params[i];
			} else {
				currentParam = null;
			}

			Tween.call(new TweenCallback() {

				@Override
				public void onEvent(int type, BaseTween<?> source) {
					try {
						if (currentParam != null) {
							inv.invokeMethod(schedulerObj, currentMethod,
									jsStage, currentParam);
						} else {
							inv.invokeMethod(schedulerObj, currentMethod,
									jsStage);
						}
					} catch (NoSuchMethodException e) {
						Gdx.app.error(MlpTss.LOG, "script method not found!", e);
					} catch (ScriptException e) {
						Gdx.app.error(MlpTss.LOG, "script error!", e);
					}

				}
			}).delay(times[i]).start(tweenManager);
		}
	}

	private ScriptEngineManager factory;

	private java.util.Map<String, ScriptEngine> scripts = new HashMap<String, ScriptEngine>();

	private ScriptManager() {
		this.factory = new ScriptEngineManager();
	}

	public ScriptEngine getScript(String path) {
		return this.scripts.get(path);
	}

	public boolean loadFile(String path) {
		try {
			ScriptEngine engine = this.factory.getEngineByName("JavaScript");

			FileHandle scriptfile = Gdx.files.internal("mods/mlp/script/"
					+ path);

			// Compilable compEngine = (Compilable) engine;
			//
			// CompiledScript compiledScript = compEngine.compile(scriptfile
			// .reader());
			// compiledScript.eval();
			engine.eval(scriptfile.reader());
			this.scripts.put(path, engine);

			return true;
		} catch (NullPointerException e) {
			Gdx.app.error(MlpTss.LOG, "failed to find script file", e);
		} catch (ScriptException e) {
			Gdx.app.error(MlpTss.LOG, "failed to load script " + path, e);
		}
		return false;
	}

	public void loadScripts(GameConfiguration config) {
		ArrayList<CharacterConfiguration> characterList = config
				.getCurrentMod().getAssetsConfiguration().getCharacters();
		for (CharacterConfiguration characterConfiguration : characterList) {
			loadFile(characterConfiguration.getAnimationPrefix() + "script.js");
		}

		ArrayList<SpecialAttackConfiguration> specialAttacks = config
				.getCurrentMod().getAssetsConfiguration().getSpecialAttacks();
		for (SpecialAttackConfiguration specialAttackConfiguration : specialAttacks) {
			loadFile(specialAttackConfiguration.getScript() + ".js");
		}

	}

}
